﻿#include "CameraCtrl.h"
#include <stdio.h>
#include "MvCameraControl.h"
#include<iostream>
#include<QDebug>
#include<opencv.hpp>
CameraCtrl::CameraCtrl()
{

  nRet = MV_OK;
  std::cout<<"camera SDK version : "<<MV_CC_GetSDKVersion ()<<"\n";

  MV_CC_DEVICE_INFO_LIST stDeviceList;memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));

  nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
  if (MV_OK != nRet)
  {
    printf("Enum Devices fail! nRet [0x%x]\n", nRet);
    is_connect =false;
    return;
  }
  printf("[device num %d]:\n", stDeviceList.nDeviceNum);
  if(stDeviceList.nDeviceNum==0) {printf("Find No camera Devices!\n");return;}

  MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[0];
  if (NULL == pDeviceInfo)
  {
    printf("NULL == pDeviceInfo!\n");
    is_connect =false;
    return;
  }
  printDeviceInfo(pDeviceInfo);


  // ch:选择设备并创建句柄 | Select device and create handle
  nRet = MV_CC_CreateHandle(&handle, pDeviceInfo);
  if (MV_OK != nRet)
  {
    printf("Create Handle fail! nRet [0x%x]\n", nRet);
    is_connect =false;
    return;
  }

  //------------------------------------------------------------
  // ch:打开设备 | Open device
  nRet = MV_CC_OpenDevice(handle);
  if (MV_OK != nRet)
  {
    printf("Open Device fail! nRet [0x%x]\n", nRet);
    is_connect =false;
    return;
  }
  is_connect = true;
  // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
  if (stDeviceList.pDeviceInfo[0]->nTLayerType == MV_GIGE_DEVICE)
  {
    int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
    if (nPacketSize > 0)
    {
      nRet = MV_CC_SetIntValue(handle,"GevSCPSPacketSize",nPacketSize);
      if(nRet != MV_OK)
      {
        printf("Warning: Set Packet Size fail nRet [0x%x]!", nRet);
      }
    }
    else
    {
      printf("Warning: Get Packet Size fail nRet [0x%x]!", nPacketSize);
    }
  }
  // ch:设置触发模式为off | en:Set trigger mode as off
  nRet = MV_CC_SetEnumValue(handle, "TriggerMode", 0);
  if (MV_OK != nRet)
  {
    printf("Set Trigger Mode fail! nRet [0x%x]\n", nRet);
    return;
  }
}

CameraCtrl::CameraCtrl(unsigned int ip1, unsigned int ip2, unsigned int ip3, unsigned int ip4)
{
  nRet = MV_OK;
  std::cout<<"camera SDK version : "<<MV_CC_GetSDKVersion ()<<"\n";

  ///------------------------网络相机--------------------------------------
  MV_CC_DEVICE_INFO stDevInfo = {0};
  MV_GIGE_DEVICE_INFO stGigEDev = {0};


  unsigned int  nIp;
  nIp = (ip1 << 24) | (ip2 << 16) | (ip3 << 8) | ip4;
  stGigEDev.nCurrentIp = nIp;

  unsigned int nIp1, nIp2, nIp3, nIp4;
  nIp1 = 255; nIp2 = 255; nIp3 = 0; nIp4 = 0;
  nIp = (nIp1 << 24) | (nIp2 << 16) | (nIp3 << 8) | nIp4;
  stGigEDev.nNetExport = nIp;


  stDevInfo.nTLayerType = MV_GIGE_DEVICE;
  stDevInfo.SpecialInfo.stGigEInfo = stGigEDev;
  nRet = MV_CC_CreateHandle(&handle, &stDevInfo);
  if (MV_OK != nRet)
  {
    printf("Create Handle fail! nRet[0x%x]\n", nRet);
    is_connect =false;
    return;
  }
  ///--------------------------------------------------------------


  //------------------------------------------------------------
  // ch:打开设备 | Open device
  nRet = MV_CC_OpenDevice(handle);
  if (MV_OK != nRet)
  {
    printf("Open Device fail! nRet [0x%x]\n", nRet);
    is_connect =false;
    return;
  }
  is_connect = true;
  // ch:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera)
  if (1)
  {
    int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
    if (nPacketSize > 0)
    {
      nRet = MV_CC_SetIntValue(handle,"GevSCPSPacketSize",nPacketSize);
      if(nRet != MV_OK)
      {
        printf("Warning: Set Packet Size fail nRet [0x%x]!", nRet);
      }
    }
    else
    {
      printf("Warning: Get Packet Size fail nRet [0x%x]!", nPacketSize);
    }
  }
  // ch:设置触发模式为off | en:Set trigger mode as off
  nRet = MV_CC_SetEnumValue(handle, "TriggerMode", 0);
  if (MV_OK != nRet)
  {
    printf("Set Trigger Mode fail! nRet [0x%x]\n", nRet);
    return;
  }
}

bool CameraCtrl::printDeviceInfo(MV_CC_DEVICE_INFO *pstMVDevInfo)
{
  if (NULL == pstMVDevInfo)
  {
    printf("The Pointer of pstMVDevInfo is NULL!\n");
    return false;
  }
  if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE)
  {
    int nIp1 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
    int nIp2 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
    int nIp3 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
    int nIp4 = (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);

    // ch:打印当前相机ip和用户自定义名字 | en:print current ip and user defined name
    printf("MV_GIGE_DEVICE\n");
    printf("  CurrentIp: %d.%d.%d.%d\n" , nIp1, nIp2, nIp3, nIp4);
    ip = QString("%1.%2.%3.%4").arg(nIp1).arg(nIp2).arg(nIp3).arg(nIp4);
    printf("  UserDefinedName: %s\n\n" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);
  }
  else if (pstMVDevInfo->nTLayerType == MV_USB_DEVICE)
  {
    printf("MV_USB_DEVICE\n");
    printf("  UserDefinedName: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);
    printf("  Serial Number: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chSerialNumber);
    printf("  Device Number: %d\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.nDeviceNumber);
  }
  else
  {
    printf("Not support.\n");
  }

  return true;
}

QString CameraCtrl::getIP()
{
  return ip;
}

unsigned int CameraCtrl::acquireImgs(void *pUser)
{
  // ch:开始取流 | en:Start grab image
  nRet = MV_CC_StartGrabbing(handle);
  if (MV_OK != nRet)
  {
    printf("Start Grabbing fail! nRet [0x%x]\n", nRet);
    return -1;
  }

  MV_FRAME_OUT stOutFrame = {0}; memset(&stOutFrame, 0, sizeof(MV_FRAME_OUT));

  while(1)
  {
    nRet = MV_CC_GetImageBuffer(pUser, &stOutFrame, 1000);
    if (nRet == MV_OK)
    {
      int width= stOutFrame.stFrameInfo.nWidth;
      int height = stOutFrame.stFrameInfo.nHeight;
      //            printf("Get One Frame: Width[%d], Height[%d], nFrameNum[%d]\n",
      //                stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum);
      //            printf("type %d \n", stOutFrame.stFrameInfo.enPixelType);

      cv::Mat img =cv::Mat(height,width,CV_8UC1,stOutFrame.pBufAddr);
      call_back_(img.clone());

    }else{
      printf("No data[0x%x]\n", nRet);
    }
    if(NULL != stOutFrame.pBufAddr)
    {
      nRet = MV_CC_FreeImageBuffer(pUser, &stOutFrame);
      if(nRet != MV_OK)
      {
        printf("Free Image Buffer fail! nRet [0x%x]\n", nRet);
      }
    }
    if(is_stop)
    {
      break;
    }
  }

  return 0;
}

bool CameraCtrl::getIs_connect() const
{
  return is_connect;
}


void CameraCtrl::startAcquirsition()
{
  if(!is_connect){
    return;
  }
  if(!is_stop){
    return;
  }
  acquisition_thread = new std::thread(&CameraCtrl::acquireImgs, this,handle);
  if (nullptr == acquisition_thread)
  {
    printf("acquisition_thread error !!! \n");
    return;
  }
  is_stop = false;
  printf("Press a key to stop grabbing.\n");
}

bool CameraCtrl::stopAcquisition()
{
  if (!is_connect)
    return false;
  if (!acquisition_thread)
    return true;

  is_stop = true;
  acquisition_thread->join();
  delete acquisition_thread;
  acquisition_thread = nullptr;

  // ch:停止取流 | en:Stop grab image
  nRet = MV_CC_StopGrabbing(handle);
  if (MV_OK != nRet)
  {
    printf("Stop Grabbing fail! nRet [0x%x]\n", nRet);
    return false;
  }

  //  // ch:关闭设备 | Close device
  //  nRet = MV_CC_CloseDevice(handle);
  //  if (MV_OK != nRet)
  //  {
  //      printf("ClosDevice fail! nRet [0x%x]\n", nRet);
  //      return false;
  //  }

  //  // ch:销毁句柄 | Destroy handle
  //  nRet = MV_CC_DestroyHandle(handle);
  //  if (MV_OK != nRet)
  //  {
  //      printf("Destroy Handle fail! nRet [0x%x]\n", nRet);
  //      return false;
  //  }
  return true;
}

float CameraCtrl::getExposureTime(void)
{
  if(!is_connect){
    return -1;
  }
  MVCC_FLOATVALUE stFloatValue = {0};

  int nRet = MV_CC_GetFloatValue(handle,"ExposureTime", &stFloatValue);
  if (MV_OK != nRet)
  {
    printf("getExposureTime error!!! %d\n", nRet);
    return -1.0;
  }

  return stFloatValue.fCurValue;
}

// ch:设置曝光时间 | en:Set Exposure Time
int CameraCtrl::setExposureTime(float time)
{
  if(!is_connect){
    return -1;
  }
  // ch:调节这两个曝光模式，才能让曝光时间生效
  // en:Adjust these two exposure mode to allow exposure time effective
  int nRet = MV_CC_SetEnumValue(handle,"ExposureMode", MV_EXPOSURE_MODE_TIMED);
  if (MV_OK != nRet){
    printf("setExposureTime error!!! %d\n", nRet);
    return -1;
  }

  nRet = MV_CC_SetEnumValue(handle,"ExposureAuto", MV_EXPOSURE_AUTO_MODE_OFF);

  nRet = MV_CC_SetFloatValue(handle,"ExposureTime", time);
  if (MV_OK != nRet){
    printf("setExposureTime error!!! %d\n", nRet);
    return -1;
  }
  return MV_OK;
}

// ch:获取增益 | en:Get Gain
float CameraCtrl::getGain(void)
{
  if(!is_connect){
    return -1;
  }
  MVCC_FLOATVALUE stFloatValue = {0};

  int nRet = MV_CC_GetFloatValue(handle,"Gain", &stFloatValue);
  if (MV_OK != nRet){
    printf("getGain error!!! %d", nRet);
    return -1;
  }
  return stFloatValue.fCurValue;
}

// ch:设置增益 | en:Set Gain
int CameraCtrl::setGain(float gain)
{
  if(!is_connect){
    return -1;
  }
  // ch:设置增益前先把自动增益关闭，失败无需返回
  //en:Set Gain after Auto Gain is turned off, this failure does not need to return
  int nRet = MV_CC_SetEnumValue(handle,"GainAuto", 0);
  nRet = MV_CC_SetFloatValue(handle,"Gain", gain);
  if (MV_OK != nRet){
    printf("setGain error!!! %d\n", nRet);
    return -1;
  }
  return nRet;
}

void CameraCtrl::registerCaptureCallback(std::function<void (cv::Mat)> call_back)
{
  if(!is_connect){
    return ;
  }
  call_back_ = call_back;
}


//============================================================================================
//          // PixelType_Gvsp_RGB8_Packed
//          // ch:像素格式转换 | en:Convert pixel format
//          unsigned int nDataSizeForRGB = width * height ;
//          unsigned char *pDataForRGB = NULL;pDataForRGB = (unsigned char*)malloc(width * height );
//          if (NULL == pDataForRGB){
//              printf("malloc pDataForRGB fail !\n");
//              break;
//          }
//          MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));

//          stConvertParam.nWidth = width;                 //ch:图像宽 | en:image width
//          stConvertParam.nHeight = height;               //ch:图像高 | en:image height
//          stConvertParam.pSrcData = stOutFrame.pBufAddr;                            //ch:输入数据缓存 | en:input data buffer
//          stConvertParam.nSrcDataLen = stOutFrame.stFrameInfo.nFrameLen;         //ch:输入数据大小 | en:input data size
//          stConvertParam.enSrcPixelType = stOutFrame.stFrameInfo.enPixelType;    //ch:输入像素格式 | en:input pixel format
////          PixelType_Gvsp_Mono8
////              PixelType_Gvsp_BGR8_Packed
//          stConvertParam.enDstPixelType = PixelType_Gvsp_Mono8; //ch:输出像素格式 | en:output pixel format
//          stConvertParam.pDstBuffer = pDataForRGB;                    //ch:输出数据缓存 | en:output data buffer
//          stConvertParam.nDstBufferSize = nDataSizeForRGB;            //ch:输出缓存大小 | en:output buffer size
//          nRet = MV_CC_ConvertPixelType(pUser, &stConvertParam);
//          if (MV_OK != nRet)
//          {
//              printf("Convert Pixel Type fail! nRet [0x%x]\n", nRet);
//              break;
//          }
//============================================================================================




//        MV_SAVE_IMG_TO_FILE_PARAM pstSaveFileParam;
//            memset(&pstSaveFileParam, 0, sizeof(MV_SAVE_IMG_TO_FILE_PARAM));

//            pstSaveFileParam.enImageType = MV_Image_Jpeg; // ch:需要保存的图像类型 | en:Image format to save
//            pstSaveFileParam.enPixelType = stConvertParam.enDstPixelType;  // ch:相机对应的像素格式 | en:Camera pixel type
//            pstSaveFileParam.nWidth      = width;         // ch:相机对应的宽 | en:Width
//            pstSaveFileParam.nHeight     = height;          // ch:相机对应的高 | en:Height
//            pstSaveFileParam.nDataLen    = stOutFrame.stFrameInfo.nFrameLen;
//            pstSaveFileParam.pData       = stConvertParam.pDstBuffer;

//            // ch:jpg图像质量范围为(50-99], png图像质量范围为[0-9] | en:jpg image nQuality range is (50-99], png image nQuality range is [0-9]
//             pstSaveFileParam.nQuality = 80;
////            if (m_nSaveImageType == MV_Image_Jpeg)
////            {
////                pstSaveFileParam.nQuality = 80;
////            }
////            else if(m_nSaveImageType == MV_Image_Png)
////            {
////                pstSaveFileParam.nQuality = 8;
////            }
//            unsigned int nFrameNum = stOutFrame.stFrameInfo.nFrameNum;
//            pstSaveFileParam.iMethodValue = 0;

//            char chImageName[256] = {0};
//            if (MV_Image_Bmp == pstSaveFileParam.enImageType)
//            {
//                sprintf_s(chImageName, 256, "Image_w%d_h%d_fn%03d.bmp", pstSaveFileParam.nWidth, pstSaveFileParam.nHeight, nFrameNum);
//            }
//            else if (MV_Image_Jpeg == pstSaveFileParam.enImageType)
//            {
//                sprintf_s(chImageName, 256, "Image_w%d_h%d_fn%03d.jpg", pstSaveFileParam.nWidth, pstSaveFileParam.nHeight, nFrameNum);
//            }
//            else if (MV_Image_Tif == pstSaveFileParam.enImageType)
//            {
//                sprintf_s(chImageName, 256, "Image_w%d_h%d_fn%03d.tif", pstSaveFileParam.nWidth, pstSaveFileParam.nHeight, nFrameNum);
//            }
//            else if (MV_Image_Png == pstSaveFileParam.enImageType)
//            {
//                sprintf_s(chImageName, 256, "Image_w%d_h%d_fn%03d.png", pstSaveFileParam.nWidth, pstSaveFileParam.nHeight, nFrameNum);
//            }
//            memcpy(pstSaveFileParam.pImagePath, chImageName, 256);

//            int nRet = MV_CC_SaveImageToFile(handle,&pstSaveFileParam);
//            if(MV_OK != nRet)
//            {
//                printf("MV_CC_SaveImageToFile fail! nRet [0x%x]\n", nRet);
//                break;
//            }
